#include "TreeMesh.h"
#include <qgl.h>
#include <stdio.h>
#include "MeshMaker.h"
#include "GL/glu.h"
#include "GL/glut.h"
#include "GL/glext.h"
#include <assert.h>
using std::cout;
using std::endl;

extern "C"{
    extern void APIENTRY glBindRenderbufferEXT (GLenum, GLuint);
    extern void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *);
    extern void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *);
    extern void APIENTRY glActiveTexture (GLenum);
    extern void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
    extern void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei);
    extern void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint);
    extern void APIENTRY glVertexAttrib3dv (GLuint , const GLdouble *);
    extern void APIENTRY glVertexAttrib3d (GLuint , const GLdouble,const GLdouble,const GLdouble );
    extern void APIENTRY glBindAttribLocation(GLuint, GLuint, const GLchar *);
    extern void APIENTRY glMultiTexCoord3f(GLenum, GLfloat, GLfloat, GLfloat);
    extern void APIENTRY glMultiTexCoord2f(GLenum, GLfloat, GLfloat);
}
TreeMesh::TreeMesh(TreeGen* gen, Renderer * rend)
{
    this->m_tris   = new vector<Tri>();
    this->m_verts  = new vector<double3>();
    this->m_tangents = new vector<double3>();
    this->m_norms  = new vector<double3>();
    this->m_texCoords = new vector<float2>();
    this->m_buds = new vector<Bud*>();

    m_leafs        = new vector<Leaf>*[NUM_LEAF_COLORS];
    m_color        = new float3[NUM_LEAF_COLORS];
    m_range        = new float3[NUM_LEAF_COLORS];
    for(int i = 0; i < NUM_LEAF_COLORS; i++)
        m_leafs[i] = new vector<Leaf>();
    render = rend;


    this->chooseLeafColor(1);





    m_shader = new QGLShaderProgram();
    m_shader->addShaderFromSourceFile(QGLShader::Fragment, "../cs224-self-organizing-trees/224_Trees/Matt_LeafShader.frag");
    m_shader->addShaderFromSourceFile(QGLShader::Vertex,   "../cs224-self-organizing-trees/224_Trees/Matt_LeafShader.vert");
    m_shader->link();

    this->makeTextures();

    buildMeshRecursivelyFromRoot(this, gen->treeRoot);

    //build(this, gen->treeRoot);

}

TreeMesh::~TreeMesh(){
    delete this->m_tris;
    delete this->m_tangents;
    delete this->m_verts;
    delete this->m_norms;
    delete this->m_texCoords;
    delete this->m_buds;
    for(int i = 0; i < NUM_LEAF_COLORS; i++){
        delete m_leafs[i];
    }
    delete[] m_leafs;
    delete[] this->m_color;
    delete[] this->m_range;
    //glReleaseTexture(this->m_tex);
}

void TreeMesh::chooseLeafColor(char choice){
    if(choice == 0){ //Spring leafs
        m_color[0] = float3(83.f/255.f,180.f/255.f,18.f/255.f);
        m_color[1] = float3(95.f/255.f,159.f/255.f,13.f/255.f);
        m_color[2] = float3(45.f/255.f,97.f/255.f,10.f/255.f);

        m_range[0] = float3(7.f/255.f,60.f/255.f,40.f/255.f);
        m_range[1] = float3(20.f/255.f,40.f/255.f,20.f/255.f);
        m_range[2] = float3(2.f/255.f,20.f/255.f,10.f/255.f);
    }
    else{ //autumn leafs
        m_color[0] = float3(183.f/255.f,23.f/255.f,9.f/255.f);
        m_color[1] = float3(243.f/255.f,176.f/255.f,72.f/255.f);
        m_color[2] = float3(232.f/255.f,218.f/255.f,8.f/255.f);

        m_range[0] = float3(20.f/255.f,85.f/255.f,62.f/255.f);
        m_range[1] = float3(-93.f/255.f,-111.f/255.f,-71.f/255.f);
        m_range[2] = float3(-63.f/255.f,-130.f/255.f,-8.f/255.f);
    }
}

void TreeMesh::draw(bool drawLeafs){

//cout << "draw shit" << endl;
    glEnable(GL_CULL_FACE);
    glEnable(GL_LIGHTING);

    //if(rand() % 20 == 1) cout << "num tris: " << this->m_tris->size() << endl;

    glColor3f(81.f/225.f,69.f/225.f,55.f/225.f);
    glColor3f(81.f/225.f,69.f/225.f,55.f/225.f);
glPushAttrib(GL_ALL_ATTRIB_BITS);


std::map<int, int> unique_vertices;
int tex_counter = 0;
Bud *curBud = m_buds->at(tex_counter);


    render->setCurrentShader("bark");
    glActiveTexture(GL_TEXTURE5);
    glBindTexture(GL_TEXTURE_2D, curBud->the_bark.normalID);
    render->shader_programs["bark"]->setUniformValue("normals", 5);
    glActiveTexture(GL_TEXTURE6);
    glBindTexture(GL_TEXTURE_2D, curBud->the_bark.barkID);
    //cout << curBud->the_bark.barkID << endl;
    render->shader_programs["bark"]->setUniformValue("bark_info",6);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,0);


    glActiveTexture(GL_TEXTURE1);
    glDisable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);



//    bool one_bool = false;
//    int ones = 0;
   //cout << "  DRAWING TREE " << endl;
   /* for (int i = 0; i < m_buds->size(); i++){
        cout << m_buds->at(i)  << endl;
    }*/
// assert(num_vertices.size() == m_buds->size());
    int triInd = 0;
    int count = 0;
    for(int i = 0; i < this->m_tris->size(); i++){

       // cout << unique_vertices.size() << "  " << num_vertices.at(tex_counter) << endl;
        if (count == num_tris.at(triInd)){
            triInd ++;
            count = 0;
             curBud = m_buds->at(triInd);
             if (render->bark_mode){
                 //cout << curBud->the_bark.age << endl;
                 glActiveTexture(GL_TEXTURE5);
                 glBindTexture(GL_TEXTURE_2D, curBud->the_bark.normalID);

                 render->shader_programs["bark"]->setUniformValue("normals", 5);
                 glActiveTexture(GL_TEXTURE6);
                 glBindTexture(GL_TEXTURE_2D, curBud->the_bark.barkID);
                // cout << curBud->the_bark.barkID << endl;
                 render->shader_programs["bark"]->setUniformValue("bark_info",6);
                 glActiveTexture(GL_TEXTURE0);
                 glBindTexture(GL_TEXTURE_2D,0);

             }
             glActiveTexture(GL_TEXTURE1);
             glDisable(GL_TEXTURE_2D);
             glBindTexture(GL_TEXTURE_2D, 0);
        }
   // cout << curBud << endl;
            glBegin(GL_TRIANGLES);
        GLfloat * tangent_data =  (GLfloat*)m_tangents->at((m_tris->at(i)).v0).data;
        GLfloat * tex_data =  (GLfloat*)m_texCoords->at((m_tris->at(i)).v0).data;
       // cout << tex_data[0] << "  " << tex_data[1] << endl;
       /* if (tex_data[0] == 0.0 && !one_bool){
            cout << "zero here" << endl;
        }
        if (tex_data[0] >.5 && !one_bool){
            cout << "ONE MODE" << endl;
            one_bool = true;
        }
        if (one_bool && tex_data[0] == 0.0){
             cout << "one here" << endl;
             glMultiTexCoord2f(GL_TEXTURE0, 1.0, tex_data[1]);
             ones ++;
        }
        else{
            glMultiTexCoord2f(GL_TEXTURE0, tex_data[0], tex_data[1]);
        }
        if (ones == 3 && one_bool){
            cout << "ZERO MODE" << endl;
            one_bool = false;
            ones = 0;
        }*/

        glMultiTexCoord2f(GL_TEXTURE0, tex_data[0], tex_data[1]);
        glMultiTexCoord3f(GL_TEXTURE1, tangent_data[0], tangent_data[1], tangent_data[2]);
        glNormal3dv(m_norms->at((m_tris->at(i)).v0).data);
        glVertex3dv(m_verts->at((m_tris->at(i)).v0).data);

        tangent_data =  (GLfloat*)m_tangents->at((m_tris->at(i)).v1).data;
        tex_data =  (GLfloat*)m_texCoords->at((m_tris->at(i)).v1).data;

       /* if (tex_data[0] == 0.0 && !one_bool){
            cout << "zero here" << endl;
        }
        if (tex_data[0] >.5 && !one_bool){
            cout << "ONE MODE" << endl;
            one_bool = true;
        }
        if (one_bool && tex_data[0] == 0.0){
             cout << "one here" << endl;
             glMultiTexCoord2f(GL_TEXTURE0, 1.0, tex_data[1]);
             ones ++;
        }
        else{
            glMultiTexCoord2f(GL_TEXTURE0, tex_data[0], tex_data[1]);
        }
        if (ones == 3 && one_bool){
            cout << "ZERO MODE" << endl;
            one_bool = false;
            ones = 0;
        }*/

        glMultiTexCoord2f(GL_TEXTURE0, tex_data[0], tex_data[1]);
        glMultiTexCoord3f(GL_TEXTURE1, tangent_data[0], tangent_data[1], tangent_data[2]);
        glNormal3dv(m_norms->at((m_tris->at(i)).v1).data);
        glVertex3dv(m_verts->at((m_tris->at(i)).v1).data);

        tangent_data =  (GLfloat*)m_tangents->at((m_tris->at(i)).v2).data;
        tex_data =  (GLfloat*)m_texCoords->at((m_tris->at(i)).v2).data;
        /*if (tex_data[0] == 0.0 && !one_bool){
            cout << "zero here" << endl;
        }
        if (tex_data[0] >.5 && !one_bool){
            cout << "ONE MODE" << endl;
            one_bool = true;
        }
        if (one_bool && tex_data[0] == 0.0){
             cout << "one here" << endl;
             glMultiTexCoord2f(GL_TEXTURE0, 1.0, tex_data[1]);
             ones ++;
        }
        else{
            glMultiTexCoord2f(GL_TEXTURE0, tex_data[0], tex_data[1]);
        }
        if (ones == 3 && one_bool){
            cout << "ZERO MODE" << endl;
            one_bool = false;
            ones = 0;
        }*/
        glMultiTexCoord2f(GL_TEXTURE0, tex_data[0], tex_data[1]);
        glMultiTexCoord3f(GL_TEXTURE1,tangent_data[0], tangent_data[1], tangent_data[2]);
        glNormal3dv(m_norms->at((m_tris->at(i)).v2).data);
        glVertex3dv(m_verts->at((m_tris->at(i)).v2).data);
      glEnd();
       count++;
       // cout << "________________" << endl;
    }

    render->releaseShader("bark");
    //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);


    if(drawLeafs){
        glEnable(GL_TEXTURE_2D);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, this->m_tex);

        glEnable(GL_BLEND);
        glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        m_shader->bind();
        m_shader->setUniformValue("tex",0);



        glDisable(GL_CULL_FACE);
        Leaf* l;


        int count = 0;
        for(int i = 0; i < NUM_LEAF_COLORS; i++){
            float3 c = this->m_color[i];
            float3 r = this->m_range[i];
            m_shader->setUniformValue("baseColor", QVector4D(c.x,c.y,c.z,1.0));
            m_shader->setUniformValue("ranger", QVector4D(r.x, r.y, r.z, 1.0));
            glBegin(GL_QUADS);
            for(int j = 0; j < this->m_leafs[i]->size(); j++){
                l = &(this->m_leafs[i]->at(j));
                glNormal3dv(l->normal.data);
                glTexCoord2f(0.0,1.0);
                glVertex3dv(l->bl.data);
                glTexCoord2f(1.0,1.0);
                glVertex3dv(l->br.data);
                glTexCoord2f(1.0,0.0);
                glVertex3dv(l->tr.data);
                glTexCoord2f(0.0,0.0);
                glVertex3dv(l->tl.data);

                count++;
            }
            glEnd();
        }


        m_shader->release();

        glDisable(GL_BLEND);
        glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
            glEnable(GL_CULL_FACE);
    }
    glEnable(GL_TEXTURE_2D);

}

void TreeMesh::makeTextures(){
    QImage img("../cs224-self-organizing-trees/textures/greyleaf_leveled.png");


    glBindTexture( GL_TEXTURE_2D, m_tex);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img.width(), img.height(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, img.bits());

    glBindTexture(GL_TEXTURE_2D, 0);
}
